package com.chucang.shucang.usr.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SmUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chucang.shucang.common.base.constant.CommonConstant;
import com.chucang.shucang.common.base.page.PageData;
import com.chucang.shucang.common.base.redis.RedisUtil;
import com.chucang.shucang.common.base.utils.DecToSfUtil;
import com.chucang.shucang.common.base.utils.R;
import com.chucang.shucang.common.mq.producer.SmsCodeProducer;
import com.chucang.shucang.common.security.annotation.Inner;
import com.chucang.shucang.common.security.utils.SecurityUtil;
import com.chucang.shucang.usr.constant.UsrCacheConstant;
import com.chucang.shucang.usr.entity.UserBaseEntity;
import com.chucang.shucang.usr.entity.UserInviteEntity;
import com.chucang.shucang.usr.exception.UsrErrorCode;
import com.chucang.shucang.usr.service.UserBaseService;
import com.chucang.shucang.usr.service.UserInviteService;
import com.chucang.shucang.usr.vo.*;
import com.chucang.shucang.usr.vo.query.UserOnSaleProductQuery;
import com.chucang.shucang.usr.vo.query.UserSoldProductQuery;
import com.github.yitter.idgen.YitIdHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 用户基础信息表
 *
 * @author flitsneak flitsneak@gmail.com
 * @since 1.0.0 2022-09-12
 */
@Slf4j
@RestController
@RequestMapping("/userbase")
@RequiredArgsConstructor
@Api(tags = "用户基础信息表")
public class UserBaseController {

    private final UserBaseService userBaseService;

    private final UserInviteService userInviteService;

    private final SmsCodeProducer smsCodeProducer;

    private final RedisUtil redisUtil;

    /**
     * 根据手机号获取用户信息
     *
     * @param cellPhoneNum 手机号
     * @return 用户信息
     */
    @Inner
    @GetMapping("/getUserInfoByCellPhone/{cellPhoneNum}")
    public R<AppUserInfo> getUserInfoByCellPhone(@PathVariable String cellPhoneNum) {
        LambdaQueryWrapper<UserBaseEntity> selectByPhone = new LambdaQueryWrapper<UserBaseEntity>()
                .eq(UserBaseEntity::getCellPhoneNum, cellPhoneNum)
                .select();
        UserBaseEntity baseEntity = userBaseService.getOne(selectByPhone);
        if (Objects.isNull(baseEntity)) {
            return R.ok(null);
        }
        AppUserInfo appUserInfo = new AppUserInfo();
        BeanUtil.copyProperties(baseEntity, appUserInfo);
        return R.ok(appUserInfo);
    }

    /**
     * 获取登录短信验证码
     *
     * @param cellPhoneNum 手机号
     * @return r
     */
    @Inner(value = false)
    @GetMapping("/getSignInSmsCode/{cellPhoneNum}")
    public R<String> getSignInSmsCode(@PathVariable String cellPhoneNum) {
        //生成6位纯数字验证码，存入redis
        String smsCode = RandomUtil.randomNumbers(6);
        redisUtil.setValue(String.format(UsrCacheConstant.USER_LOGIN_SMS_CODE, cellPhoneNum), smsCode, 3, TimeUnit.MINUTES);
        //发送获取验证码请求
        smsCodeProducer.sendSmsCode(cellPhoneNum, smsCode);
        return R.ok();
    }

    /**
     * 发送注册验证码
     *
     * @param cellPhoneNum 手机号
     * @return r
     */
    @Inner(value = false)
    @ApiOperation(value = "发送注册短信验证码")
    @ApiImplicitParam(name = "cellPhoneNum", value = "手机号", required = true, dataType = "String", dataTypeClass = String.class)
    @GetMapping("/getSignUpSmsCode/{cellPhoneNum}")
    public R<String> getSignUpSmsCode(@PathVariable String cellPhoneNum) {
        String smsCode = RandomUtil.randomNumbers(6);
        redisUtil.setValue(String.format(UsrCacheConstant.USER_SIGN_UP_SMS_CODE, cellPhoneNum), smsCode, 3, TimeUnit.MINUTES);
        smsCodeProducer.sendSmsCode(cellPhoneNum, smsCode);
        return R.ok();
    }

    /**
     * 验证注册信息
     *
     * @param userSignUpVO usr
     * @return r
     */
    @Inner(value = false)
    @PostMapping("/checkSignUpInfo")
    public R<String> checkSignUpInfo(@Valid @RequestBody UserSignUpVO userSignUpVO) {
        //校验验证码
        Object object = redisUtil.getObject(String.format(UsrCacheConstant.USER_SIGN_UP_SMS_CODE, userSignUpVO.getCellPhoneNum()));
        if (Objects.isNull(object)) {
            return R.failed(UsrErrorCode.INVALID_SIGN_UP_SMS_CODE.getCode(), UsrErrorCode.INVALID_SIGN_UP_SMS_CODE.getMsg());
        }
        //清空缓存
        redisUtil.deleteKey(String.format(UsrCacheConstant.USER_SIGN_UP_SMS_CODE, userSignUpVO.getCellPhoneNum()));
        if (!object.toString().equals(userSignUpVO.getSmsCode())) {
            return R.failed(UsrErrorCode.INVALID_SIGN_UP_SMS_CODE.getCode(), UsrErrorCode.INVALID_SIGN_UP_SMS_CODE.getMsg());
        }
        //校验邀请码
        if (!CharSequenceUtil.isBlank(userSignUpVO.getInviteCode())) {
            UserBaseEntity baseEntity = userBaseService.getByInviteCode(userSignUpVO.getInviteCode());
            if (Objects.isNull(baseEntity)) {
                return R.failed(UsrErrorCode.INVALID_INVITE_CODE.getCode(), UsrErrorCode.INVALID_INVITE_CODE.getMsg());
            }
        }
        //校验手机号，账号是否已经注册，账号是否被注销，是否被禁止
        UserBaseEntity byMobile = userBaseService.getByMobile(userSignUpVO.getCellPhoneNum());
        if (Objects.nonNull(byMobile)) {
            if (byMobile.getStatus() != CommonConstant.STATUS_NORMAL || byMobile.getDelFlag() != CommonConstant.STATUS_NORMAL) {
                return R.failed(UsrErrorCode.USER_ACCOUNT_PROHIBIT.getCode(), UsrErrorCode.USER_ACCOUNT_PROHIBIT.getMsg());
            }
            return R.failed(UsrErrorCode.USER_ACCOUNT_EXIST.getCode(), UsrErrorCode.USER_ACCOUNT_EXIST.getMsg());
        }
        //消息存入缓存 5分钟，等待下一步设置密码
        redisUtil.setValue(String.format(UsrCacheConstant.USER_SIGN_UP_INFO, userSignUpVO.getCellPhoneNum()), userSignUpVO, 5, TimeUnit.MINUTES);
        return R.ok();
    }

    /**
     * 正式注册
     *
     * @param userRegisterVO 注册信息
     * @return r
     */
    @Inner(value = false)
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/doRegister")
    public R<String> doRegister(@Valid @RequestBody UserRegisterVO userRegisterVO) {
        //redis取出用户信息
        Object object = redisUtil.getObject(String.format(UsrCacheConstant.USER_SIGN_UP_INFO, userRegisterVO.getCellPhoneNum()));
        if (Objects.isNull(object)) {
            return R.failed(UsrErrorCode.USER_REGISTER_INFO_EXPIRED.getCode(), UsrErrorCode.USER_REGISTER_INFO_EXPIRED.getMsg());
        }
        //清空缓存
        redisUtil.deleteKey(String.format(UsrCacheConstant.USER_SIGN_UP_INFO, userRegisterVO.getCellPhoneNum()));
        //存入数据库
        UserBaseEntity userBaseEntity = new UserBaseEntity();
        BeanUtil.copyProperties(object, userBaseEntity);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        userBaseEntity.setPassword(encoder.encode(userRegisterVO.getPassword()));
        //生成id
        long id = YitIdHelper.nextId();
        userBaseEntity.setId(id);
        //生成邀请码
        userBaseEntity.setInviteCode(DecToSfUtil.toInviteSf(id));
        userBaseEntity.setUsername("藏家#" + DecToSfUtil.toNameSf(id));
        userBaseEntity.setIsFaceAuth(0);
        userBaseEntity.setIsRealAuth(0);
        userBaseEntity.setShowOwnCollection(0);
        userBaseEntity.setShowSellCollection(0);

        userBaseService.save(userBaseEntity);

        if (!CharSequenceUtil.isBlank(((UserSignUpVO) object).getInviteCode())) {
            //插入邀请码信息
            UserInviteEntity userInviteEntity = new UserInviteEntity();
            userInviteEntity.setInviteCode(((UserSignUpVO) object).getInviteCode());
            userInviteEntity.setInviteeId(id);

            userInviteService.save(userInviteEntity);
        }
        return R.ok();
    }

    /**
     * 获取重置密码的验证码
     *
     * @param cellPhoneNum 手机号
     * @return r
     */
    @Inner(value = false)
    @GetMapping("/getResetPwdSmsCode/{cellPhoneNum}")
    public R<String> getResetPwdSmsCode(@PathVariable String cellPhoneNum) {
        //生成6位纯数字验证码，存入redis
        String smsCode = RandomUtil.randomNumbers(6);
        redisUtil.setValue(String.format(UsrCacheConstant.USER_RESET_PWD_SMS_CODE, cellPhoneNum), smsCode, 3, TimeUnit.MINUTES);
        //发送获取验证码请求
        smsCodeProducer.sendSmsCode(cellPhoneNum, smsCode);
        return R.ok();
    }

    /**
     * 重置密码
     *
     * @param userResetPwdVO urp
     * @return r
     */
    @Inner(value = false)
    @PostMapping("/resetPwd")
    public R<String> resetPwd(@Valid @RequestBody UserResetPwdVO userResetPwdVO) {
        Object object = redisUtil.getObject(String.format(UsrCacheConstant.USER_RESET_PWD_SMS_CODE, userResetPwdVO.getCellPhoneNum()));
        if (Objects.isNull(object)) {
            return R.failed(UsrErrorCode.USER_RESET_PWD_CODE_EXPIRED.getCode(), UsrErrorCode.USER_RESET_PWD_CODE_EXPIRED.getMsg());
        }
        redisUtil.deleteKey(String.format(UsrCacheConstant.USER_RESET_PWD_SMS_CODE, userResetPwdVO.getCellPhoneNum()));
        if (!userResetPwdVO.getSmsCode().equals(object.toString())) {
            return R.failed(UsrErrorCode.USER_RESET_PWD_CODE_EXPIRED.getCode(), UsrErrorCode.USER_RESET_PWD_CODE_EXPIRED.getMsg());
        }
        //重置密码
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String newPwd = bCryptPasswordEncoder.encode(userResetPwdVO.getNewPassword());
        LambdaUpdateWrapper<UserBaseEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(UserBaseEntity::getCellPhoneNum, userResetPwdVO.getCellPhoneNum())
                .set(UserBaseEntity::getPassword, newPwd);
        userBaseService.update(lambdaUpdateWrapper);
        return R.ok();
    }

    /**
     * 根据用户id 查找用户基础信息
     *
     * @param id 用户id
     * @return r
     */
    @Inner
    @GetMapping("/getUserBaseInfoById/{id}")
    public R<UserBaseEntity> getUserBaseInfoById(@PathVariable Long id) {
        UserBaseEntity byId = userBaseService.getById(id);
        return R.ok(byId);
    }

    /**
     * 获取用户基础信息
     *
     * @param id 用户id
     * @return r
     */
    @GetMapping("/getUserInfoById/{id}")
    public R<UserBaseInfoVO> getUserInfoById(@PathVariable Long id) {
        UserBaseEntity byId = userBaseService.getById(id);
        if (Objects.isNull(byId)) {
            log.error("获取用户：{}，信息失败！", id);
            return R.failed(UsrErrorCode.USER_NOT_FOUNT.getCode(), UsrErrorCode.USER_NOT_FOUNT.getMsg());
        }
        UserBaseInfoVO userBaseInfoVO = new UserBaseInfoVO();
        BeanUtil.copyProperties(byId, userBaseInfoVO);
        return R.ok(userBaseInfoVO);
    }

    /**
     * 获取设置信息
     *
     * @param id 用户id
     * @return r
     */
    @GetMapping("/getUserSettingInfo/{id}")
    public R<UserSettingInfoVO> getUserSettingInfo(@PathVariable Long id) {
        UserBaseEntity byId = userBaseService.getById(id);
        if (Objects.isNull(byId)) {
            log.error("获取用户：{}，信息失败！", id);
            return R.failed(UsrErrorCode.USER_NOT_FOUNT.getCode(), UsrErrorCode.USER_NOT_FOUNT.getMsg());
        }
        UserSettingInfoVO userSettingInfoVO = new UserSettingInfoVO();
        BeanUtil.copyProperties(byId, userSettingInfoVO);
        return R.ok(userSettingInfoVO);
    }

    /**
     * 用户已售产品信息
     *
     * @param userSoldProductQuery upq
     * @return r
     */
    @PostMapping("/soldProductPage")
    public R<PageData<UserSoldProductResVO>> soldProductPage(@Valid @RequestBody UserSoldProductQuery userSoldProductQuery) throws ExecutionException, InterruptedException {
        PageData<UserSoldProductResVO> pageData = userBaseService.soldProductPage(userSoldProductQuery);
        return R.ok(pageData);
    }

    /**
     * 用户在售商品信息
     *
     * @param userOnSaleProductQuery usq
     * @return r
     */
    @PostMapping("/onSaleProductPage")
    public R<PageData<UserOnSaleProductResVO>> onSaleProductPage(@Valid @RequestBody UserOnSaleProductQuery userOnSaleProductQuery) throws ExecutionException, InterruptedException {
        PageData<UserOnSaleProductResVO> pageData = userBaseService.onSaleProductPage(userOnSaleProductQuery);
        return R.ok(pageData);
    }

    /**
     * 撤销寄售
     *
     * @param userWithdrawProductConsignVO uwp
     * @return r
     */
    @PostMapping("/withdrawProductConsign")
    public R<String> withdrawProductConsign(@Valid @RequestBody UserWithdrawProductConsignVO userWithdrawProductConsignVO) {
        userBaseService.withdrawProductConsign(userWithdrawProductConsignVO);
        return R.ok();
    }

    /**
     * 设置寄售密码
     *
     * @param userSetSecPasswordVO usp
     * @return r
     */
    @PostMapping("/setSecPassword")
    public R<String> setSecPassword(@Valid @RequestBody UserSetSecPasswordVO userSetSecPasswordVO) {
        userBaseService.setSecPassword(userSetSecPasswordVO);
        return R.ok();
    }

    /**
     * 校验用户二级密码
     *
     * @param userCheckSecPasswordVO ucp
     * @return r
     */
    @PostMapping("/checkSecPassword")
    public R<String> checkSecPassword(@Valid @RequestBody UserCheckSecPasswordVO userCheckSecPasswordVO) {
        String code = userBaseService.checkSecPassword(userCheckSecPasswordVO);
        if (CharSequenceUtil.isBlank(code)) {
            return R.failed();
        }
        return R.ok(code);
    }

    /**
     * 旧二级密码修改
     *
     * @param userResetSecPasswordByOldVO urp
     * @return r
     */
    @PostMapping("/resetSecPasswordByOld")
    public R<String> resetSecPasswordByOld(@Valid @RequestBody UserResetSecPasswordByOldVO userResetSecPasswordByOldVO) {
        Object object = redisUtil.getObject(String.format(UsrCacheConstant.USER_CHECK_SEC_PASSWORD, userResetSecPasswordByOldVO.getUserId()));
        if (Objects.isNull(object)) {
            return R.failed(UsrErrorCode.USER_RESET_SEC_PWD_OLD_EXPIRED.getCode(), UsrErrorCode.USER_RESET_SEC_PWD_OLD_EXPIRED.getMsg());
        }
        redisUtil.deleteKey(String.format(UsrCacheConstant.USER_CHECK_SEC_PASSWORD, userResetSecPasswordByOldVO.getUserId()));
        if (object.toString().equals(userResetSecPasswordByOldVO.getCode())) {
            LambdaUpdateWrapper<UserBaseEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserBaseEntity::getId, userResetSecPasswordByOldVO.getUserId())
                    .set(UserBaseEntity::getSecPassword, SmUtil.sm3(userResetSecPasswordByOldVO.getSecPassword()));
            userBaseService.update(updateWrapper);
            return R.ok();
        }
        return R.failed(UsrErrorCode.USER_RESET_SEC_PWD_OLD_EXPIRED.getCode(), UsrErrorCode.USER_RESET_SEC_PWD_OLD_EXPIRED.getMsg());
    }

    /**
     * 获取重置二级密码验证码
     *
     * @param cellPhoneNum 手机号
     * @return r
     */
    @GetMapping("/getResetSecPwdSmsCode/{cellPhoneNum}")
    public R<String> getResetSecPwdSmsCode(@PathVariable String cellPhoneNum) {
        //生成6位纯数字验证码，存入redis
        String smsCode = RandomUtil.randomNumbers(6);
        redisUtil.setValue(String.format(UsrCacheConstant.USER_RESET_SEC_PASSWORD_CODE, cellPhoneNum), smsCode, 3, TimeUnit.MINUTES);
        //发送获取验证码请求
        smsCodeProducer.sendSmsCode(cellPhoneNum, smsCode);
        return R.ok();
    }

    /**
     * 手机验证码重置二级密码
     *
     * @param userResetSecPasswordBySmsCodeVO urs
     * @return r
     */
    @PostMapping("/resetSecPasswordBySmsCode")
    public R<String> resetSecPasswordBySmsCode(@Valid @RequestBody UserResetSecPasswordBySmsCodeVO userResetSecPasswordBySmsCodeVO) {
        Object object = redisUtil.getObject(String.format(UsrCacheConstant.USER_RESET_SEC_PASSWORD_CODE, userResetSecPasswordBySmsCodeVO.getCellPhoneNum()));
        if (Objects.isNull(object)) {
            return R.failed(UsrErrorCode.USER_RESET_SEC_PWD_CODE_EXPIRED.getCode(), UsrErrorCode.USER_RESET_SEC_PWD_CODE_EXPIRED.getMsg());
        }
        redisUtil.deleteKey(String.format(UsrCacheConstant.USER_RESET_SEC_PASSWORD_CODE, userResetSecPasswordBySmsCodeVO.getCellPhoneNum()));
        if (!object.toString().equals(userResetSecPasswordBySmsCodeVO.getSmsCode())) {
            return R.failed(UsrErrorCode.USER_RESET_SEC_PWD_CODE_EXPIRED.getCode(), UsrErrorCode.USER_RESET_SEC_PWD_CODE_EXPIRED.getMsg());
        }
        LambdaUpdateWrapper<UserBaseEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserBaseEntity::getCellPhoneNum, userResetSecPasswordBySmsCodeVO.getCellPhoneNum())
                .set(UserBaseEntity::getSecPassword, SmUtil.sm3(userResetSecPasswordBySmsCodeVO.getSecPassword()));
        userBaseService.update(updateWrapper);
        return R.ok();
    }

    @Inner
    @PostMapping("/listUserBaseInfo")
    public R<List<UserBaseEntity>> listUserBaseInfo(@RequestBody Set<Long> idSet) {
        List<UserBaseEntity> userBaseEntities = userBaseService.listByIds(idSet);
        return R.ok(userBaseEntities);
    }

    /**
     * 更改用户名
     *
     * @param userBaseInfoChangeUserNameVO
     * @return
     */
    @PostMapping("/changeUsername")
    public R<String> changeUsername(@Valid @RequestBody UserBaseInfoChangeUserNameVO userBaseInfoChangeUserNameVO) {
        Long id = SecurityUtil.getUser().getId();
        LambdaUpdateWrapper<UserBaseEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserBaseEntity::getId, id)
                .set(UserBaseEntity::getUsername, userBaseInfoChangeUserNameVO.getUsername());
        userBaseService.update(updateWrapper);
        return R.ok();
    }

}